/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1/commercial
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may use this file in compliance with the License.
 * Alternatively, if you can't copy with the License, namely if you do not
 * want to provide source code of your modifications to this file, you may
 * negotiate a commercial licence with the initial developer.
 * You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is COID.
 *
 * The Initial Developer of the Original Code is
 * PosAm.
 * Portions created by the Initial Developer are Copyright (C) 2003
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * Brano Kemen
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#ifndef __COID_SERVER_SERVICEINST__HEADER_FILE__
#define __COID_SERVER_SERVICEINST__HEADER_FILE__

#include "coid/comm/binstream/binstream.h"
#include "coid/comm/binstream/netstream.h"
#include "serverface.h"
#include "mxsingleton.h"
#include "coid/svc/instance.h"

namespace coid {


#define IFCLIST_T   MXSINGLETON_T(t_ifclist)
#define IFCLIST     MXSINGLETON(t_ifclist)

////////////////////////////////////////////////////////////////////////////////
struct ServiceInstanceCoid : CoidNode
{
    struct hash_voidp
    {
        typedef void* key_type;

        size_t operator() (void* str) const
        {
            return 3141592653UL*(uints)str;
        }
    };
    typedef keywordmap<void*,ServiceInstanceCoid*,hash_voidp>   t_ifclist;


    void*   _instptr;
    cmd_interface   _cmdin;

    const ServiceDescriptor* _desc;
    uint    _flags;
    uint    _owner;
    //uint    _nref;

    enum {
        fAUTHENTIFIED               = 1,
        fAUTOINSTANCE               = 2,

        fALLOW_SHARED               = 4,

        xLOG                        = 0x0300,
        fLOG_CALL                   = 0x0100, ///< log the calls of this method
        fLOG_DURATION               = 0x0200, ///< if also the fLOG_CALL enabled, measure and log the call duration
    };

    bool is_authentified() const                { return (_flags & fAUTHENTIFIED) != 0; }
    bool is_allowed_shared_access() const       { return (_flags & fALLOW_SHARED) != 0; }
    bool is_autoinstance() const                { return (_flags & fAUTOINSTANCE) != 0; }

    ServiceInstanceCoid( const ServiceDescriptor* desc, const charstr& path )
    {
        _instptr = 0;
        _desc = desc;
#ifdef _DEBUG
        _flags = fLOG_CALL;
        set_verbosity(3);
#else
        _flags = 0;
        set_verbosity(1);
#endif
        _owner = UMAX32;
        //_nref = 0;
        _path = path;

        _cmdin.init( get_cmdin(), this );
		_mutex.set_name( "ServiceInstanceCoid" );
    }

    ~ServiceInstanceCoid()
    {
    }

    virtual opcd initialize()
    {
        charstr ver;
        charstr name = _desc->_name;
        name << " " << _desc->_version.get_version(ver);
        if( _flags & fAUTOINSTANCE )
            name << " (auto)";
		_mutex.set_name( name.ptr() );
        set_name(name);
        return 0;
    }

    bool owning_itself() const              { return _owner == _id || _owner == UMAX32; }

	void init( void* objptr )
	{
		_instptr = objptr;
        //++_nref;
	}

    opcd connect_interface( void* pifc );
    opcd disconnect_interface( void* pifc );
    opcd disconnect_interface_catch();

    virtual uint get_method_id( const token& name )
    {
        if( name.first_char() == '~' )
        {
            if( name == "~destroy" )
                return StdProtocolMethod::DISCONNECT;
            return UMAX32;
        }
        return _desc->get_method_id( name );
    }

    virtual opcd dispatch( uint method, binstream& bin, metastream* meta );
    virtual opcd list_cmds( const token& cmd, dynarray<charstr>& cmds ) const;
    virtual opcd dispatch_cmd( const token& cmd, command_tokens& arg, txtstream& reply );

    opcd dispatch_call( binstream& bin, uint method, metastream* meta );


    virtual token short_name() const            { return _desc->_shortname; }
    virtual token class_name() const            { return _desc->_name; }
    virtual const version& get_version() const  { return _desc->_version; }

    static cmd_interface_vtbl* get_cmdin();

    ////////////////////////////////////////////////////////////////////////////////
    // interface lookup functions - back mapping f

    static ServiceInstanceCoid* find_iface_inst( void* ifc )
    {
        IFCLIST_T ifcl = IFCLIST;
        ServiceInstanceCoid** p = ifcl->find(ifc);
        if(p)
            return *p;
        return 0;
    }

    bool insert_iface_inst( void* ifc )
    {
        IFCLIST_T ifcl = IFCLIST;
        return ifcl->insert( ifc, this );
    }

    static bool erase_iface_inst( void* ifc )
    {
        IFCLIST_T ifcl = IFCLIST;
        return ifcl->erase(ifc);
    }



public:
    //IMPLEMENTS_VIRTUAL_INTERFACE_ttree_ifc_BEGIN_PURE(ServiceInstanceCoid,"0.0",CoidNode);
    IMPLEMENTS_VIRTUAL_INTERFACE_ttree_ifc_BEGIN_PURE(ServiceInstanceCoid,"0.0",CoidNode);
    IMPLEMENTS_VIRTUAL_INTERFACE_ttree_ifc_END;

    virtual NodeClass GET_NODECLASS()
    {
        return SINGLETON(ClassRegister<ttree_ifc>).find_or_create( GET_INTERFACE().get_iface(), this );
    }


    //operator token () const                 { return _desc->_name; }
    //operator const version& () const        { return _desc->_version; }
    token get_class_name(const void*p) const    { return _desc->_name; }
    const version& get_version(const void*p) const  { return _desc->_version; }
};

} // namespace coid

#endif //__COID_SERVER_SERVICEINST__HEADER_FILE__
